texture base_Tex;
sampler2D baseMap = sampler_state
{
   Texture = (base_Tex);
};
float factor;
struct PS_INPUT 
{
   float2 Texcoord : TEXCOORD0;
};
float testChannel(float channel, float tmp1, float tmp2, float tmp3c)
{
   if (tmp3c < 0.0)
      tmp3c += 1.0;
   else if (tmp3c > 1.0)
      tmp3c -= 1.0;
      
   if( (6.0f * tmp3c) < 1 )
      channel = tmp1 + (tmp2-tmp1) * 6.0f * tmp3c;
   else if( (2.0f * tmp3c) < 1 )
      channel = tmp2;
   else if( (3.0f * tmp3c) < 2 )
      channel = tmp1 + (tmp2-tmp1) * ( (2.0f/3.0f)-tmp3c ) * 6.0f;
   else
      channel = tmp1;
      
   return channel;
}
float4 convertToRgb(float4 hsl)
{
   float4 rgb = float4(0.0f, 0.0f, 0.0f, 1.0f);
   float hue = hsl.x;
   float sat = hsl.y;
   float lum = hsl.z;
   if( sat == 0.0f )
   {
      rgb.r = lum;
      rgb.g = lum;
      rgb.b = lum;
   }
   else
   {
      float tmp2;
      float3 tmp3;
      if( lum < 0.5f )
         tmp2 = lum * (1.0f + sat);
      else
         tmp2 = (lum + sat) - (lum * sat);
      float tmp1 = 2.0f * lum - tmp2;
      tmp3.x = hue + (1.0f / 3.0f);
      tmp3.y = hue;
      tmp3.z = hue - (1.0f / 3.0f);
      rgb.r = testChannel(rgb.r, tmp1, tmp2, tmp3.x);
      rgb.g = testChannel(rgb.g, tmp1, tmp2, tmp3.y);
      rgb.b = testChannel(rgb.b, tmp1, tmp2, tmp3.z);
   }
   return rgb;
}
// 1 Convert to HSL color space
// 2 Multiply luminance factor
// 3 Convert to RGB color space
float4 correctContrast(float4 rgb, float factor)
{   
   float pMin;
   float pMax;
   float hue;   // hue
   float sat;   // saturation
   float lum;   // luminance
   pMin = min( min(rgb.r, rgb.g), rgb.b );
   pMax = max( max(rgb.r, rgb.g), rgb.b );
   lum = ( pMax + pMin ) / 2.0f;
   if( (pMax-pMin) == 0.0f )
   {
         // if pMax and pMin are the same (greyscale)
         sat = 0.0f;
         hue = 0.0f;
   }
   else
   {
      if( lum < 0.5f )
      {
         sat = ( pMax - pMin ) / ( pMax + pMin );
      }
      else // lum >= 0.5f
      {
         sat = ( pMax - pMin ) / ( 2.0f - pMax - pMin );
      }
      float rDelta = ( ( (pMax - rgb.r) / 6.0f ) + ( (pMax-pMin) / 2.0f ) ) / (pMax-pMin);
      float gDelta = ( ( (pMax - rgb.g) / 6.0f ) + ( (pMax-pMin) / 2.0f ) ) / (pMax-pMin);
      float bDelta = ( ( (pMax - rgb.b) / 6.0f ) + ( (pMax-pMin) / 2.0f ) ) / (pMax-pMin);
      if( rgb.r == pMax )
         hue = bDelta - gDelta;
      else if( rgb.g == pMax )
         hue = (1.0f / 3.0f) + rDelta - bDelta;
      else if( rgb.b == pMax )
         hue = (2.0f / 3.0f) + gDelta - rDelta;
      
      if( hue < 0.0f )
         hue += 1.0f;
      else if( hue > 1.0f )
         hue -= 1.0f;
   }
   // adjust luminance by factor
   float2 inLum;
   float2 outLum;
   float1 kl = 0.0f;
   float1 bl = 0.0f;
   if( factor > 1.0f )
      inLum = float2( 0.5f - ( 0.5f / factor ), 0.5f + ( 0.5f / factor ) );
   else
      outLum = float2( 0.5 - ( 0.5 * factor ), 0.5 + ( 0.5 * factor ) );
   // calculate correction parameters
   float inLumMax = max(inLum[0], inLum[1]);
   float inLumMin = min(inLum[0], inLum[1]);
   float outLumMax = max(outLum[0], outLum[1]);
   float outLumMin = min(outLum[0], outLum[1]);
   if( inLumMax != inLumMin )
   {
      kl = (outLumMax-outLumMin) / (inLumMax-inLumMin);
      bl = outLumMin - kl * inLumMin;
   }
   // correct actual luminance
   if( lum >= inLumMax )
      lum = outLumMax;
   else if( lum <= inLumMin )
      lum = outLumMin;
   else
      lum = ( kl * lum ) + bl;
   // Create HSL color
   float4 hsl = float4( hue, sat, lum, 1.0f );
   return convertToRgb(hsl);
}
float4 Pixel_Shader_ps_main( PS_INPUT Input ) : COLOR0
{
   float4 base = tex2D( baseMap, Input.Texcoord );
   // Apply filter
   base = correctContrast(base, factor);
   return base;
}
technique ContrastCorrection
{
   pass Pass_0
   {
      PixelShader = compile ps_2_a Pixel_Shader_ps_main();
   }
}

